
#ifndef __WEBSERVER__
#define __WEBSERVER__

#include <iostream>
#include <unordered_map>
#include <unistd.h>
#include <thread>
#include <signal.h>
#include <functional>
#include <sys/socket.h>
#include <sys/timerfd.h>

#include "ThreadPool.hpp"
#include "Entrance.hpp"
#include "TcpSocket.hpp"

#define QUEUE_TASK_NUM 526      // 任务队列最大数
#define EPOLL_EVENT_MAXNUM 1024   // epoll事件就绪队列单次最大量
#define WEB_SOCKET_TIME_OVER 10 // socket超时 10 s 关闭连接
#define TIME_FD_CHECK 1         // timefd 5秒触发一次超时检测

// 增加单例模式
class webserver
{
    typedef ThreadPool<Thread_Task *> thread_pool;
    typedef std::function<void(ConnectData *)> fd_func;

private:
    int _port = -3;
    int _server_listen_socket = -3;
    thread_pool *st = nullptr;

    int _efd;                               // epoll实例描述符
    int _timerfd;                           // 定时器实例描述符
    struct epoll_event *_epoll_event_array; // 事件就绪缓冲区
    size_t max_num;                         // 最大事件就绪量

    std::unordered_map<size_t, ConnectData *> fd_dispath; // epoll

    

public:
    webserver()
    {
        signal(SIGPIPE, SIG_IGN);
        // 防止send，向关闭管道写入，导致webserver崩溃
    }

    ~webserver()
    {
        if (_server_listen_socket > 0)
            close(_server_listen_socket);
        if (_efd > 0)
            close(_efd);
        if (_epoll_event_array != nullptr)
            delete[] _epoll_event_array;
    }

    int GetEfd() { return _efd; }

    // 初始化webserver
    void initial(int _port, thread_pool *th_pool)
    {
        _epoll_event_array = new epoll_event[EPOLL_EVENT_MAXNUM];
        if (_epoll_event_array == nullptr)
        {
            WARN("event array new fail");
            exit(3);
        }

        max_num = EPOLL_EVENT_MAXNUM;

        MySocket tool;
        _server_listen_socket = tool._socket_set();
        // 设置复用端口号
        int tmp = 1;
        if (setsockopt(_server_listen_socket, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) < 0)
            WARN("setsockopt fail");

        tool.bind_set(_server_listen_socket, _port);
        INFO("服务端初始化成功");

        // 更新线程池句柄
        st = th_pool;
        // 创建epoll实例
        _efd = MyEpoll::CreateEpoll();
        // 创建定时器实例
        init_timerfd();
    }

    void work_begin()
    {
        // 1.初始化listen_socket
        MySocket::listen_run(_server_listen_socket);
        MyEpoll::SetSocketNoHang(_server_listen_socket); // 为epollET设置非阻塞

        ConnectData *listen_connection = new ConnectData(_server_listen_socket);
        listen_connection->SetCallBack(this,
                                       std::bind(&webserver::AddSocketoEpoll, this, std::placeholders::_1),
                                       nullptr, nullptr);

        // 将listen_socket以ET模式添加
        MyEpoll::CtlEpoll(_efd, _server_listen_socket, EPOLL_CTL_ADD, EPOLLIN | EPOLLET); // epollET，只报告一次
        fd_dispath.insert({_server_listen_socket, listen_connection});

        // 2. 添加定时器描述符
        ConnectData *Time_fd_server = new ConnectData(_timerfd);
        Time_fd_server->SetCallBack(this,
                                    std::bind(&webserver::Timerfd_check_t, this, std::placeholders::_1),
                                    nullptr, nullptr);
        // 将定时器描述符添加到监听中
        MyEpoll::CtlEpoll(_efd, _timerfd, EPOLL_CTL_ADD, EPOLLIN); // 定时器只监听读就绪事件
        fd_dispath.insert({_timerfd, Time_fd_server});

        FAIL("lis:%d, time:%d", _server_listen_socket, _timerfd);

        while (1)
        {
            LoopOnce();
        }
    }

    bool is_exit_func_tree(int data)
    {
        return fd_dispath.find(data) != fd_dispath.end();
    }
private:
    // 循环主程序
    void LoopOnce()
    {
        int n = MyEpoll::WaitEpoll(_efd, _epoll_event_array, max_num, 1000);
        switch (n)
        {
        case -1:
            WARN("epoll wait fail");
            break;
        case 0:
            // Logmessage(INFO, "timeout");
            break;
        default:
            for (int i = 0; i < n; i++)
            {
                int fd = _epoll_event_array[i].data.fd;
                uint32_t revent = _epoll_event_array[i].events;
                if (revent & (EPOLLERR | EPOLLHUP))
                {
                    if (is_exit_func_tree(fd))
                    {
                        ConnectData *tmp = fd_dispath[fd];
                        tmp->_except_event(tmp);
                    }
                }

                // 写事件就绪
                if (revent & EPOLLOUT)
                {
                    if (is_exit_func_tree(fd))
                    {
                        ConnectData *tmp = fd_dispath[fd];
                        std::thread from_out(tmp->_write_event, tmp);
                        from_out.detach();
                    }
                }

                // 读事件就绪
                if (revent & EPOLLIN)
                {
                    // 文件描述符方法树中查找, 并执行方法
                    if (is_exit_func_tree(fd))
                    {
                        //看看是不是定时器事件
                        if (fd == _timerfd)
                        {
                            uint64_t expirations;
                            read(_timerfd, &expirations, sizeof(expirations)); // 读取到期次数
                        }
                        ConnectData *tmp = fd_dispath[fd];
                        tmp->_read_event(tmp);
                    }
                }
            }
            break;
        }
    }

    void init_timerfd()
        {
            // 创建定时器文件描述符
            _timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
            if (_timerfd == -1)
            {
                FAIL("timerfd_create fail");
                exit(EXIT_FAILURE);
            }

            // 设置定时器，每秒触发一次
            struct itimerspec its = {};
            its.it_interval.tv_sec = TIME_FD_CHECK; // 每5秒触发一次
            its.it_value.tv_sec = TIME_FD_CHECK;    // 一直触发下去
            if (timerfd_settime(_timerfd, 0, &its, nullptr) == -1)
            {
                FAIL("timerfd_settime fail");
                exit(EXIT_FAILURE);
            }
        }
    // 普通socket设置方法表
    void AddSocketoEpoll(ConnectData *it)
    {
        sockaddr_in cline;
        uint16_t cline_prot;
        int actual_socket = MySocket::accept_run(_server_listen_socket, &cline, &cline_prot);
        if (actual_socket != -1)
        {
            INFO("connect success 标识符:%d", actual_socket);
        }

        // 设置阻塞式,非阻塞式比较复杂
        // MyEpoll::SetSocketNoHang(actual_socket);
        ConnectData *socket_tmp = new ConnectData(actual_socket);
        socket_tmp->SetCallBack(this,
                                std::bind(&webserver::Listen_func_t, this, std::placeholders::_1),
                                std::bind(&webserver::write_func_t, this, std::placeholders::_1),
                                std::bind(&webserver::Except_func_t, this, std::placeholders::_1));
        MyEpoll::CtlEpoll(_efd, actual_socket, EPOLL_CTL_ADD, EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLET);
        if (is_exit_func_tree(actual_socket))
            return;
        fd_dispath.insert({actual_socket, socket_tmp});
    }

    // 正常socket读时间就绪 == 普通socket发送请求报文，该处理了
    void Listen_func_t(ConnectData *it)
    {
        int fd = it->_fd;
        INFO("task push :%d", fd);
        if (st->Get_queue_task_reserver_size() < QUEUE_TASK_NUM)
        {
            // INFO("task push");
            Thread_Task *task = new Thread_Task(fd, fd_dispath[fd]);
            st->push(task);
            st->swap_queue(QUEUE_TASK_NUM);
        }
    }

    void write_func_t(ConnectData *it)
    {
        int socket = it->_fd;
        // 检测是否是关闭socket导致触发的写事件
        if (it->sendbuff.size() == 0)
            return;
        INFO("写事件就绪喽：%d",it->_fd);
        while (1)
        {
            int ret = send(socket, it->sendbuff.c_str(), it->sendbuff.size(), 0);
            if (ret == -1)
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    INFO("write once full======================== ");
                    break; // 发送缓冲区满了，等待下次再发
                }
                else if (errno == EINTR)
                    continue;
                else
                    return;
            }
            else if (ret <= it->sendbuff.size())
            {
                it->sendbuff.erase(0, ret);
                if (it->sendbuff.empty())
                    break;
            }
        }

        if (it->sendbuff.empty())
        {
            INFO("剩余数据发送完毕");
            Except_func_t(fd_dispath[socket]);
            // INFO("断开 ");
        }
    }

    void Except_func_t(ConnectData *it)
    {
        int fd = it->_fd;
        // 删除该普通socket的epoll关心
        MyEpoll::DelEpoll(_efd, fd);
        delete fd_dispath[fd];
        fd_dispath[fd] = nullptr;
        fd_dispath.erase(fd);
        close(fd);
    }

    void Timerfd_check_t(ConnectData *it)
    {
        time_t current_time = time(nullptr); // 获取当前时间
        // 遍历所有连接的最后活动时间
        for (auto tmp = fd_dispath.begin(); tmp != fd_dispath.end();)
        {
            if (tmp->first == _server_listen_socket || tmp->first == _timerfd)
            {
                ++tmp;
            }
            else if (difftime(current_time, tmp->second->_last_time) > WEB_SOCKET_TIME_OVER)
            {
                INFO("超时关闭: %d,剩余:%d", tmp->first, fd_dispath.size());
                Except_func_t(tmp++->second);
            }
            else
            {
                ++tmp; // 继续检查下一个连接
            }
        }
    }
};

bool MyEpoll::EnableReadWrite(ConnectData *con, bool read, bool write)
{
    uint32_t tmp = EPOLLET | EPOLLERR;
    if (read)
        tmp |= EPOLLIN;
    if (write)
        tmp |= EPOLLOUT;

    if (con->_fd > 1024)
        return false;
    epoll_event room;
    room.data.fd = con->_fd;
    room.events = tmp;

    INFO("socket %d 重新设置 write事件 %d", con->_fd, write);

    if (epoll_ctl(con->_websever->GetEfd(), EPOLL_CTL_MOD, con->_fd, &room) == -1)
    {
        FAIL("EnableReadWrite fail %s", strerror(errno));
        exit(3);
    }
    return true;
}

void *Thread_Task::operator()()
{
    HttpWork it(socket, _con);
    if (STOP == 1)
    {
        STOP = 0;
        WARN("请求读取异常,取消连接");
        return nullptr;
    }
    it.PaseHttpRequest_main();
    it.BuildHttpRespose_main();
    if (STOP == 1)
    {
        WARN("send 异常");
    }

    // send未发送完成,等待再发送
    if (STOP == -1)
    {
        WARN("等待重发, 先不关闭close");
    }
    else
    {
        MyEpoll::EnableReadWrite(_con, true, false);
        // 长连接，待机超时，刷新
        _con->_last_time = std::time(nullptr);
        INFO("%d:响应完成，进入等待", socket);
        // 正常，异常退出，扩展：等待超时
    }
}

#endif
